
package taskmanager;

import mpiserver.MpiEvent;
import mpiserver.MpiListener;
import Network.IArbitrationController;
import Network.IModeWork;
import Network.NetworkLogic;
import java.rmi.RemoteException;
import java.util.LinkedList;
import java.util.Vector;
import mpiserver.IMpiServer;

/**
 * Планировщик задач
 * Этот класс является основным в пакете "taskmanager"
 * инкапсулирует локальный и глобальный планировщики
 * @author Aleksey ID = 2001
 */
public class TaskManager implements ITaskManager,IModeWork {
    /** планировщих верхнего уровня */
    private GlobalTaskManager globalTM;
    /** планировщих нижнего уровня */
    private LocalTaskManager localTM;
    /** режим работы */
    private int mode;
    /** ссылка на объект управления сетью */
    private NetworkLogic netlogic=null;
    /** события, не отправленные из-за ошибки сети */
    private LinkedList<TaskManagerWaitedEvent> waitedEvents;
    /** сервер mpi */
    private IMpiServer mpiServer;
    /** обработчики событий ведомых серверов */
    private Vector<MpiListener> listeners;


    /**
     * Обработчик событий о состоянии задач
     * класс перенаправляет события нужным обработчикам в зависимости от
     * режима работы сервера.
     * В автономном режиме события пересылаются на планировщик нижнего уровня
     * В режиме арбитра - на планировщик верхнего уровня
     * В режиме ведомого - на удаленный объект арбитра
     * В неопределенном режиме игнорируются
     */
    private class TMListener implements MpiListener{
        /**
         * Событие завершения задачи
         * @param e событие
         */
        public void endingTask(MpiEvent e) {   
            switch(mode){
                case AUTONOMIC_MODE: //автономный режим
                    localTM.endingTask(e); break;
                case ARBITRATOR_MODE: //режим арбитра
                    globalTM.endingTask(e); break;
                case SLAVE_MODE: //режим ведомого
                    try {
                        //отпраить событие на арбитр
                        netlogic.getS2S().getIArbitrator().endingTask(e);
                    } catch (RemoteException ex) {
                        //при невозможности отправки, добавить событие в очередь
                        waitedEvents.push(new TaskManagerWaitedEvent(
                                TaskManagerWaitedEvent.ENDING,e));
                    }
            }
            //отправить событие обработчикам
            for(MpiListener l:listeners) l.endingTask(e);
        }// end endingTask method

        /**
         * Ошибка запуска задачи
         * @param e объект события
         */
        public void errorTask(MpiEvent e) {
                        switch(mode){
                case AUTONOMIC_MODE: //автономный режим
                    localTM.errorTask(e); break;
                case ARBITRATOR_MODE: //режим арбитра
                    globalTM.errorTask(e); break;
                case SLAVE_MODE: //режим ведомого
                    try {
                        //отпраить событие на арбитр
                        netlogic.getS2S().getIArbitrator().errorTask(e);
                    } catch (RemoteException ex) {
                        //при невозможности отправки, добавить событие в очередь
                        waitedEvents.push(new TaskManagerWaitedEvent(
                                TaskManagerWaitedEvent.ENDING,e));
                    }
            }
            //отправить событие обработчикам
            for(MpiListener l:listeners) l.errorTask(e);
        }
    } //end TMListener class
    /**
     * конструктор
     * по умолчнанию в режиме UNCHECKED игнорирует все запросы
     * @param mpiServer модуль управления сервером mpi
     */
    public TaskManager(IMpiServer mpiServer){
        this.mpiServer=mpiServer;
        //Добавить слушателя в модуль mpi
        mpiServer.addMpiListener(new TMListener());
        //инициализация структур
        mode=UNCHECKED;
        listeners=new Vector<MpiListener>();
        globalTM=null;
        localTM=null;
        waitedEvents=new LinkedList<TaskManagerWaitedEvent>();
    }
    
    /**
     * Передать сетевой модуль планировщику
     * @param netLogic модуль сетевого взаимодействия
     */
    public void initNetwork(NetworkLogic netLogic){
        this.netlogic=netLogic;
    }
    
    /**
     * Повторная отправка отложенных событий
     * @return true - отложенные события полностью отправлены, false - отправлены
     * не все события
     */
    public boolean sendWaitedEvents(){
        try {
            //получить удаленный объет арбитра
            IArbitrationController arbitr = netlogic.getS2S().getIArbitrator();
            //перебрать все отложенные события
            while(!waitedEvents.isEmpty()){
                //прочитать первое событие
                TaskManagerWaitedEvent e=waitedEvents.peekFirst();
                //отправка на арбитр
                switch(e.getReason()){
                    case TaskManagerWaitedEvent.ENDING: //выполнение заявки
                        arbitr.endingTask(e.getEvent());  break;
                }
                //изъять событие из очереди
                waitedEvents.pollFirst();
            }
            return true;
        } catch (RemoteException ex) {return false;}
    }

    /**
     * Определить наличие отложенных событий
     * @return true - есть отложенные события, false - нет отложенных событий
     */
    public boolean hasWaitedEvents(){
        return !waitedEvents.isEmpty();
    }

    /**
     * Удалить ожидающие события
     */
    public void clearWaitedEvents(){
        waitedEvents.clear();
    }

    /**
     * Задать режим работы (автономный,арбитр,ведомый или не определено)
     * @param mode режим работы
     * @return true - успешное изменение режима, false - в системе есть мешающие
     * переводу заявки
     */
    public boolean setMode(int mode){
        if(this.mode==mode) return true;
        //неустановленый режим - удалить планировщики
        if(mode==UNCHECKED){
            if(globalTM!=null && !globalTM.isEmpty()){ return false; }
            if(localTM!=null && !localTM.isEmpty()){ return false; }
            globalTM=null;
            localTM=null;
        }
        //автономный режим - оставить планировщих нижнего уровня без изменений
        else if(mode ==AUTONOMIC_MODE){
            if(globalTM!=null && !globalTM.isEmpty()){ return false; }
            localTM=new LocalTaskManager(mpiServer);
            globalTM=null;
        }
        //режим ведомого сервера - оставить пустой планировщих нижнего
        else if(mode ==SLAVE_MODE){
            if(netlogic==null) return false;
            if(globalTM!=null && !globalTM.isEmpty()){ return false; }
            if(localTM!=null && !localTM.isEmpty()){ return false; }
            localTM=new LocalTaskManager(mpiServer);
            globalTM=null;
        }
        //режим арбитра - создать пустые планировщики обоих уровней
        else if(mode ==ARBITRATOR_MODE){
            if(netlogic==null) return false;
            if(globalTM!=null && !globalTM.isEmpty()){ return false; }
            if(localTM!=null && !localTM.isEmpty()){ return false; }
            localTM=new LocalTaskManager(mpiServer);
            globalTM=new GlobalTaskManager(netlogic,localTM);
            netlogic.getS2S().getMyArbitrationController().addMpiListener(
                    new TMListener());
        }
        //нераспознанный режим
        else
            return false;
        this.mode=mode;
        return true;
    }

    /**
     * Запросить режим работы (автономный,арбитр,ведомый или не определено)
     * @param mode режим работы
     * @return режим работы
     */
    public int getMode(){
        return mode;
    }

    /**
     * Зпросить планировщик верхнего уровня
     * @return планировщик верхнего уровня
     */
    public IGlobalTaskManager getGlobalTM(){
        return globalTM;
    }

    /**
     * Запросить планировщик нижнего уровня
     * @return планировщик нижнего уровня
     */
    public ILocalTaskManager getLocalTM(){
        return localTM;
    }

    /**
     * Запросить планировщик нижнего уровня ведомого сервера
     * @return планировщик нижнего уровня ведомого сервера
     */
    public ISlaveTaskManager getSlaveTM(){
        return localTM;
    }

    /**
     * Добавить обработчик событий модуля mpi
     * @param listener обработчик события
     */
    public void addMpiListener(MpiListener listener) {
        if(listener==null) throw new NullPointerException();
        //проверить на наличие такого обработчика, если его нет - добавить
        if(listeners.contains(listener)) return;
        listeners.add(listener);
    }

//    /**
//     * Запросить количество задач в планировщике
//     * @return число задач в планировщике
//     */
//    public int getTaskCount(){
//        if(mode==UNCHECKED) return 0;
//        //вернуть количество задач планировщика верхнего уровня, если нет - нижнего
//        if(globalTM!=null) return globalTM.getTaskCount();
//        else return localTM.getTaskCount();
//    }
//
//    /**
//     * Проверить наличие задач в планировщике
//     * @return true - здач нет, иначе false
//     */
//    public boolean isEmpty(){
//        if(mode==UNCHECKED) return true;
//        //вернуть наличие задач планировщика верхнего уровня, если нет - нижнего
//        if(globalTM!=null) return globalTM.isEmpty();
//        else return localTM.isEmpty();
//    }
//
//    /**
//     * Добавить задачу в планировщик
//     * @param task задача, не null !
//     * @return true - задача добавлена, false - задача с указанным id уже есть
//     */
//    public boolean addTask(JTask task){
//        if(mode==UNCHECKED) return false;
//        //перенаправление вызова на глобальный или локальный планировщики
//        if(mode==ARBITRATOR_MODE) return globalTM.addTask(task);
//        else return localTM.addTask(task);
//    }
//
//    /**
//     * Удалить задачу из планировщика
//     * Процессы связанные с задачей уничтожаются
//     * @param taskID идентификатор задачи
//     * @return true - задача удалена, false - задачи нет
//     */
//    public boolean removeTask(long taskID){
//        if(mode==UNCHECKED) return false;
//        //перенаправление вызова на глобальный или локальный планировщики
//        if(mode==ARBITRATOR_MODE) return globalTM.removeTask(taskID);
//        else return localTM.removeTask(taskID);
//    }
//
//    /**
//     * Остановить выполнение задачи
//     * @param taskID идентификатор задачи
//     * @return true - задача остановлена, false - задачи нет
//     */
//    public boolean stopTask(long taskID){
//        if(mode==UNCHECKED) return false;
//        //перенаправление вызова на глобальный или локальный планировщики
//        if(mode==ARBITRATOR_MODE) return globalTM.stopTask(taskID);
//        else return localTM.stopTask(taskID);
//    }
//
//    /**
//     * Запросить задачу
//     * @param taskID идентификатор задачи
//     * @return задача или null в случае отсутствия
//     */
//    public JTask getTask(long taskID){
//        if(mode==UNCHECKED) return null;
//        //перенаправление вызова на глобальный или локальный планировщики
//        if(mode==ARBITRATOR_MODE) return globalTM.getTask(taskID);
//        else return localTM.getTask(taskID);
//    }
//
//    /**
//     * Запросить идентификаторы задач в планировщике
//     * Если планировщик находится в режиме арбитра будут возвращены все задачи
//     * системы, иначе задачи текущего сервера
//     * @return массив идентификаторов задач
//     */
//    public long[] getAllTasks(){
//        if(mode==UNCHECKED) return null;
//        //перенаправление вызова на глобальный или локальный планировщики
//        if(mode==ARBITRATOR_MODE) return globalTM.getAllTasks();
//        else return localTM.getAllTasks();
//    }
//
//    /**
//     * Установить максимальное количество активных задач для планировщика
//     * нижнего уровня
//     * @param max максимально количество активных задач
//     */
//    public void setMaxActiveCount(int max){
//        if(mode==UNCHECKED) return;
//        localTM.setMaxActiveCount(max);
//    }
//
//    /**
//     * Запросить максимальное количество активных задач планировщика нижнего
//     * уровня
//     * @return максимально количество активных задач
//     */
//    public int getMaxActiveCount(){
//        if(mode==UNCHECKED) return 0;
//        return localTM.getMaxActiveCount();
//    }
//
//    /**
//     * Проверить наличие задачи
//     * @param taskID идентификатор задачи
//     * @return true - задача присутствует, false иначе
//     */
//    public boolean containsTask(long taskID){
//        if(mode==UNCHECKED) return false;
//        //перенаправление вызова на глобальный или локальный планировщики
//        if(mode==ARBITRATOR_MODE) return globalTM.containsTask(taskID);
//        else return localTM.containsTask(taskID);
//    }
//
//    /**
//     * Запросить количество активных задач для планировщика
//     * нижнего уровня
//     * @return количество активных задач
//     */
//    public int getActiveCount(){
//        if(mode==UNCHECKED) return 0;
//        return localTM.getActiveCount();
//    }
}
